package com.open.cloud.rbac.utils;


import io.jsonwebtoken.*;
import io.jsonwebtoken.security.Keys;
import org.apache.commons.codec.binary.Base64;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;

import javax.crypto.spec.SecretKeySpec;
import java.security.Key;
import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.Optional;

/**
 * @author ：sun_bin
 * @date ：Created in 2019/2/28 19:46
 */
public class SecurityUtil {

    private SecurityUtil() {
        throw new IllegalStateException("Utility class");
    }

    /**
     * 获取当前登录用户用户名
     *
     * @return
     */
    public static Optional<String> getCurrentUserLogin() {
        if (null != RequestContextHolder.getRequestAttributes()) {
            return Optional.ofNullable(
                    (String)
                            RequestContextHolder.getRequestAttributes()
                                    .getAttribute(
                                            PredefinedHeaderKey.USERACCOUNT_HEADER, RequestAttributes.SCOPE_REQUEST));
        } else {
            return getCurrentUserLoginFromThreadLocal();
        }
    }

    private static Optional<String> getCurrentUserLoginFromThreadLocal() {
        Object o = ThreadLocalUtil.get(PredefinedHeaderKey.USERACCOUNT_HEADER);
        if (null != o) {
            return Optional.ofNullable((String) o);
        } else {
            return Optional.empty();
        }
    }

    /**
     * 获取当前登录用户信息
     * @return
     */
    public static Optional<Claims> getCurrentUser() {
        if (null != RequestContextHolder.getRequestAttributes()) {
            return Optional.ofNullable(
                    (Claims)
                            RequestContextHolder.getRequestAttributes()
                                    .getAttribute(
                                            PredefinedHeaderKey.AUTH_USER_INFO, RequestAttributes.SCOPE_REQUEST));
        } else {
            return getCurrentUserFromThreadLocal();
        }
    }

    private static Optional<Claims> getCurrentUserFromThreadLocal() {
        Object o = ThreadLocalUtil.get(PredefinedHeaderKey.AUTH_USER_INFO);
        if (null != o) {
            return Optional.ofNullable((Claims) o);
        } else {
            return Optional.empty();
        }
    }

    /**
     * 获取RequestId
     *
     * @return
     */
    public static Optional<String> getRequestId() {
        if (null != RequestContextHolder.getRequestAttributes()) {
            return Optional.ofNullable(
                    (String)
                            RequestContextHolder.getRequestAttributes()
                                    .getAttribute(
                                            PredefinedHeaderKey.WEB_REQUEST_ID, RequestAttributes.SCOPE_REQUEST));
        } else {
            return getRequestIdFromThreadLocal();
        }
    }

    public static Optional<String> getTxContext() {
        if (null != RequestContextHolder.getRequestAttributes()) {
            return Optional.ofNullable(
                    (String)
                            RequestContextHolder.getRequestAttributes()
                                    .getAttribute(PredefinedHeaderKey.TX_CONTEXT, RequestAttributes.SCOPE_REQUEST));
        } else {
            return getTxContextFromThreadLocal();
        }
    }

    private static Optional<String> getTxContextFromThreadLocal() {
        Object o = ThreadLocalUtil.get(PredefinedHeaderKey.TX_CONTEXT);
        if (null != o) {
            return Optional.ofNullable((String) o);
        } else {
            return Optional.empty();
        }
    }

    private static Optional<String> getRequestIdFromThreadLocal() {
        Object o = ThreadLocalUtil.get(PredefinedHeaderKey.WEB_REQUEST_ID);
        if (null != o) {
            return Optional.ofNullable((String) o);
        } else {
            return Optional.empty();
        }
    }

    /**
     * 获取当前登录用户的JWT
     *
     * @return
     */
    public static Optional<String> getCurrentUserJWT() {
        if (null != RequestContextHolder.getRequestAttributes()) {
            return Optional.ofNullable(
                    (String)
                            RequestContextHolder.getRequestAttributes()
                                    .getAttribute(
                                            PredefinedHeaderKey.AUTHORIZATION_HEADER, RequestAttributes.SCOPE_REQUEST));
        }
        return getCurrentUserJWTFromThreadLocal();
    }

    private static Optional<String> getCurrentUserJWTFromThreadLocal() {
        Object o = ThreadLocalUtil.get(PredefinedHeaderKey.AUTHORIZATION_HEADER);
        if (null != o) {
            return Optional.ofNullable((String) o);
        } else {
            return Optional.empty();
        }
    }

    /**
     * 生成密钥Key
     *
     * @param secret 经过Base64编码的密钥字符串
     * @return
     */
    public static Optional<Key> generateSecretKey(String secret) {
        Key key = Keys.hmacShaKeyFor(Base64.decodeBase64(secret));
        return Optional.ofNullable(key);
    }

    /**
     * 生成密钥Key
     *
     * @param secret        经过Base64编码的密钥字符串
     * @param algorithmName 加密算法
     * @return
     */
    public static Optional<Key> generateSecretKey(String secret, String algorithmName) {
        SignatureAlgorithm algorithm =
                SignatureAlgorithm.forName(algorithmName);
        Key key = new SecretKeySpec(Base64.decodeBase64(secret), algorithm.getJcaName());
        return Optional.ofNullable(key);
    }


    /**
     * 生成RSA公钥
     *
     * @param publicKey 经过Base64编码的RSA公钥字符串
     * @return
     * @throws Exception
     */
    public static Optional<Key> generatePublicKey(String publicKey) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(publicKey);
        X509EncodedKeySpec keySpec = new X509EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PublicKey pubKey = keyFactory.generatePublic(keySpec);
        return Optional.ofNullable(pubKey);
    }

    /**
     * 生成RSA私钥
     *
     * @param privateKey 经过Base64编码的RSA私钥字符串
     * @return
     * @throws Exception
     */
    public static Optional<Key> generatePrivateKey(String privateKey) throws Exception {
        byte[] keyBytes = Base64.decodeBase64(privateKey);
        PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(keyBytes);
        KeyFactory keyFactory = KeyFactory.getInstance("RSA");
        PrivateKey priKey = keyFactory.generatePrivate(keySpec);
        return Optional.ofNullable(priKey);
    }

    public static Optional<String> generateToken(Claims claims, Key key) {
        JwtBuilder jwtBuilder = Jwts.builder();
        jwtBuilder.setClaims(claims);
        if (null != key) {
            jwtBuilder.signWith(key);
        }
        String token = jwtBuilder.compact();
        return Optional.ofNullable(token);
    }

    public static Optional<Claims> parseToken(String jwtStr, Key key) throws Exception {
        if (!jwtStr.isEmpty()) {
            // 按照密钥解析
            JwtParserBuilder jwtParser = Jwts.parserBuilder();
            if (null != key) {
                jwtParser.setSigningKey(key);
            }
            Claims claims = jwtParser.setAllowedClockSkewSeconds(60).build().parseClaimsJws(jwtStr).getBody();
            return Optional.ofNullable(claims);
        }
        return Optional.empty();
    }

//  public static Map<String, Claim> parseToken(String jwtStr, Key key) {
////    public static Optional<Claims> parseToken(String jwtStr, Key key) {
////    if (!jwtStr.isEmpty()) {
////      // 按照密钥解析
////      JwtParser jwtParser = Jwts.parser();
////      if (null != key) {
////        jwtParser.setSigningKey(key);
////      }
////      Claims claims = jwtParser.setAllowedClockSkewSeconds(60).parseClaimsJws(jwtStr).getBody();
////      return Optional.ofNullable(claims);
////    }
////    return Optional.empty();
//
//      JWTVerifier verifier = JWT.require(Algorithm.HMAC256("1646462850bac7d5cc29e26f7d067a9d")).build();
//      DecodedJWT jwt = verifier.verify(jwtStr);
//      Map<String, Claim> claims = jwt.getClaims();
//
//      return claims;
//  }

}
